package com.ocom.mqsimple.business.facecheck;

import com.alibaba.fastjson.JSON;
import com.ocom.common.request.simple.FaceCheckRequest;
import com.ocom.common.utils.bdface.GsonUtils;
import com.ocom.common.utils.bdface.HttpUtil;
import com.ocom.common.vo.PersonVo;
import com.ocom.common.vo.webapi.BDFaceToken;
import com.ocom.mqsimple.config.FaceCkeckConfig;
import com.ocom.mqsimple.feign.HumanClientService;
import com.ocom.mqsimple.feign.PayConfigClientService;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Component
public class FaceCheckConsumerMqListener {

	private Logger logger = LoggerFactory.getLogger(FaceCheckConsumerMqListener.class);

	@Value("${save.path}")
	String path;

	@Value("${lib.path}")
	String libPath;

	@Autowired
	private HumanClientService humanClientService;

	@Autowired
	private PayConfigClientService payConfigClientService;



	/**
	 * 把该监听命名为A监听
	 * 监听队列  远程服务支付接口发送消息  该队列会接受
	 * [message, headers, channel]
	 *
	 * @return {@link }
	 * @throws
	 */
	@RabbitListener(queues = FaceCkeckConfig.FACE_CHECK_QUEUE)
	public void process(Message message, @Headers Map<String, Object> headers, Channel channel) throws Exception {
		logger.info("faceCheck 消费中");
		logger.info("message【{}】", message);
		String humanMessage = new String(message.getBody(), StandardCharsets.UTF_8);
		//TODO 数据库操作样例
		logger.info("faceCheck-start:【{}】", humanMessage);
		logger.info("System.currentTimeMillis()【{}】", System.currentTimeMillis());

		FaceCheckRequest faceCheckRequest = JSON.parseObject(humanMessage, FaceCheckRequest.class);

//		String fileName = (faceCheckRequest.getUrl().split("/"))[faceCheckRequest.getUrl().split("/").length-1];
//
//		String filePath = path + RandomUtil.getRandomString(10) + fileName;

		Boolean b= false;

		try {

//			File pic = DownloadFileUtils.downloadFile(faceCheckRequest.getUrl(), filePath);
//			FaceEngineV41 hrFaceEngine = new FaceEngineV41();
//			b = hrFaceEngine.check(pic,libPath);

			String ytr = faceDetect(faceCheckRequest.getUrl());
			BDFaceToken bdFaceToken = JSON.parseObject(ytr, BDFaceToken.class);

			if(bdFaceToken.getErrorCode()!=0){
				b=false;
			}else{
				List<String>  stringList =new ArrayList<>();
				Float faceProbability = Float.parseFloat( bdFaceToken.getResult().getFaceList().get(0).getFaceProbability().toString());
				if(faceProbability!=1f){
					stringList.add("人脸置信度不为1,当前:"+faceProbability);
				}
				String gsType = (String) bdFaceToken.getResult().getFaceList().get(0).getGlasses().get("type");
				if(!gsType.equals("none")){
					stringList.add("检测戴眼镜不通过，当前:"+gsType);
				}

				Float rightEye =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getEyeStatus().get("right_eye").toString()) ;
				if(rightEye<0.9f){
					stringList.add("右眼闭合度检测不通过，当前:"+rightEye);
				}

				Float leftEye =Float.parseFloat( bdFaceToken.getResult().getFaceList().get(0).getEyeStatus().get("left_eye").toString()) ;
				if(leftEye<0.9f){
					stringList.add("左眼闭合度检测不通过，当前:"+leftEye);
				}
				String faceType =(String) bdFaceToken.getResult().getFaceList().get(0).getFaceType().get("type");
				if(!faceType.equals("human")){
					stringList.add("人脸类型不通过，当前:"+faceType);
				}
				Float probability =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getFaceType().get("probability").toString()) ;
				if(probability<0.7f){
					stringList.add("人脸类型判断正确的置信度检测不通过，当前:"+probability);
				}
				Integer mask =(Integer)bdFaceToken.getResult().getFaceList().get(0).getMask().get("type");
				if(mask==1){
					stringList.add("口罩检测，当前检测到口罩");
				}
				//	objectMap.put("口罩置信度，范围0~1",bdFaceToken.getResult().getFaceList().get(0).getMask().get("probability"));
				Float pleftEye =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getQuality().getOcclusion().get("left_eye").toString()) ;
				if(pleftEye>0.2f){
					stringList.add("左眼遮挡比例检测不通过，当前:"+pleftEye);
				}
				Float prightEye =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getQuality().getOcclusion().get("right_eye").toString()) ;
				if(prightEye>0.2f){
					stringList.add("右眼遮挡比例检测不通过，当前:"+prightEye);
				}

				Float pnose =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getQuality().getOcclusion().get("nose").toString()) ;
				if(pnose>0.2f){
					stringList.add("鼻子遮挡比例检测不通过，当前:"+pnose);
				}
				Float pmouth =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getQuality().getOcclusion().get("mouth").toString()) ;
				if(pmouth>0.2f){
					stringList.add("嘴巴遮挡比例检测不通过，当前:"+pmouth);
				}
				Float pleftCheek =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getQuality().getOcclusion().get("left_cheek").toString()) ;
				if(pleftCheek>0.2f){
					stringList.add("左脸颊遮挡比例检测不通过，当前:"+pleftCheek);
				}
				Float prightCheek =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getQuality().getOcclusion().get("right_cheek").toString()) ;
				if(prightCheek>0.2f){
					stringList.add("右脸颊遮挡比例检测不通过，当前:"+prightCheek);
				}
				Float pchinContour =Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getQuality().getOcclusion().get("chin_contour").toString()) ;
				if(pchinContour>0.2f){
					stringList.add("下巴遮挡比例检测不通过，当前:"+pchinContour);
				}
				Float blur = Float.parseFloat(bdFaceToken.getResult().getFaceList().get(0).getQuality().getBlur().toString()) ;
				if(blur>0.2f){
					stringList.add("人脸模糊程度检测不通过，当前:"+blur);
				}
				Float completeness =Float.parseFloat( bdFaceToken.getResult().getFaceList().get(0).getQuality().getCompleteness().toString()) ;
				if(completeness!=1f){
					stringList.add("人脸完整度检测不通过，当前:"+completeness);
				}
				if(stringList.size()==0){
					b= true;
				}

			}

		} catch (Exception e) {
			logger.error("消息处理失败:{{}}", humanMessage);
			logger.info("出现异常队列消息开始进入死信队列{{}}", e);
			b= true;
		}
//		finally {
//			try {
//				new File(filePath).delete();
//			} catch (Exception e) {
//				logger.error("照片检测 删除失败:【{}】", e);
//			}
//
//		}

		//检测
		if (!b) {
			faceCheckRequest.setUrl("");
		}

		try {
			PersonVo personVo = new PersonVo();
			personVo.setComId(faceCheckRequest.getComId());
			personVo.setPId(faceCheckRequest.getPId());
			personVo.setPPhotoUrl2(faceCheckRequest.getUrl());

			humanClientService.modifyPhoto(personVo);

			payConfigClientService.setXFWhiteInfo(faceCheckRequest.getComId(), faceCheckRequest.getPId(), 0l);
		} catch (Exception e) {
			logger.info("faceErr-出现异常队列消息开始进入死信队列{{}}", e);
		}

		channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
		logger.info("faceCheck-end:【{}】", humanMessage);
		logger.info("System.currentTimeMillis()【{}】", System.currentTimeMillis());
	}

	/**
	 * 把该监听命名为B监听
	 * 监听死信队列  远程服务支付接口发送消息  该队列会接受
	 * [message, headers, channel]
	 *
	 * @return {@link }
	 * @throws
	 */
	@RabbitListener(queues = FaceCkeckConfig.FACE_CHECK_DIE_QUEUE)
	public void processForDie(Message message, @Headers Map<String, Object> headers, Channel channel) throws Exception {
		//死信队列放弃
		channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
		logger.info("人臉检查死信队列放弃 ， 【{}】", message);
	}


	public static String getAuth() {
		// 官网获取的 API Key 更新为你注册的
		String clientId = "gyDN7d1nnqGgrGf1ezonroCH";
		// 官网获取的 Secret Key 更新为你注册的
		String clientSecret = "sjO8vOE6LEAkaVBRiednpzgL9TT0Ofca";
		return getAuth(clientId, clientSecret);
	}

	/**
	 * 获取API访问token
	 * 该token有一定的有效期，需要自行管理，当失效时需重新获取.
	 *
	 * @param ak - 百度云官网获取的 API Key
	 * @param sk - 百度云官网获取的 Securet Key
	 * @return assess_token 示例：
	 * "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
	 */
	public static String getAuth(String ak, String sk) {
		// 获取token地址
		String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
		String getAccessTokenUrl = authHost
				// 1. grant_type为固定参数
				+ "grant_type=client_credentials"
				// 2. 官网获取的 API Key
				+ "&client_id=" + ak
				// 3. 官网获取的 Secret Key
				+ "&client_secret=" + sk;
		try {
			URL realUrl = new URL(getAccessTokenUrl);
			// 打开和URL之间的连接
			HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
			connection.setRequestMethod("GET");
			connection.connect();
			// 获取所有响应头字段
			Map<String, List<String>> map = connection.getHeaderFields();
			// 遍历所有的响应头字段
			for (String key : map.keySet()) {
				System.err.println(key + "--->" + map.get(key));
			}
			// 定义 BufferedReader输入流来读取URL的响应
			BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
			String result = "";
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
			/**
			 * 返回结果示例
			 */
			System.err.println("result:" + result);
			JSONObject jsonObject = new JSONObject(result);
			String access_token = jsonObject.getString("access_token");
			return access_token;
		} catch (Exception e) {
			System.err.printf("获取token失败！");
			e.printStackTrace(System.err);
		}
		return null;
	}

	public static String faceDetect(String faceUrl) {
		// 请求url
		String url = "https://aip.baidubce.com/rest/2.0/face/v1/feature";
		try {
			Map<String, Object> map = new HashMap<>();
			map.put("image", faceUrl);
			map.put("image_type", "URL");
			map.put("version", "4300");

			String param = GsonUtils.toJson(map);

			// 注意这里仅为了简化编码每一次请求都去获取access_token，线上环境access_token有过期时间， 客户端可自行缓存，过期后重新获取。
			String accessToken = getAuth();

			String result = HttpUtil.post(url, accessToken, "application/json", param);
			System.out.println(result);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

}
